package com.lbd.gulimall.ware.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.lbd.common.exception.RRException;
import com.lbd.common.to.sf.fare.CommonSFReq;
import com.lbd.common.to.sf.fare.CommonSFResp;
import com.lbd.common.utils.R;
import com.lbd.gulimall.ware.feign.CartFeignService;
import com.lbd.gulimall.ware.feign.MemberFeignService;
import com.lbd.gulimall.ware.feign.WareSkuFeignService;
import com.lbd.gulimall.ware.properties.SFProperties;
import com.lbd.gulimall.ware.service.WareSkuService;
import com.lbd.gulimall.ware.vo.CartItemVO;
import com.lbd.gulimall.ware.vo.FareVO;
import com.lbd.gulimall.ware.vo.MemberReceiveAddressVO;
import com.sf.csim.express.service.CallExpressServiceTools;
import com.sf.csim.express.service.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lbd.common.utils.PageUtils;
import com.lbd.common.utils.Query;

import com.lbd.gulimall.ware.dao.WareInfoDao;
import com.lbd.gulimall.ware.entity.WareInfoEntity;
import com.lbd.gulimall.ware.service.WareInfoService;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

@Slf4j
@Service("wareInfoService")
public class WareInfoServiceImpl extends ServiceImpl<WareInfoDao, WareInfoEntity> implements WareInfoService {
    @Autowired
    private ThreadPoolExecutor executor;
    @Autowired
    private MemberFeignService memberFeignService;
    @Autowired
    private CartFeignService cartFeignService;
    @Autowired
    private WareSkuService wareSkuService;
    @Autowired
    private WareSkuFeignService wareSkuFeignService;
    @Autowired
    private SFProperties sfProperties;

    @Autowired

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareInfoEntity> page = this.page(
                new Query<WareInfoEntity>().getPage(params),
                new QueryWrapper<WareInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryByCondition(Map<String, Object> params) {
        QueryWrapper<WareInfoEntity> wrapper = new QueryWrapper<>();
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)) {
            wrapper.eq("id", key)
                    .or()
                    .like("name", key)
                    .or()
                    .like("address", key)
                    .or()
                    .eq("areacode", key);
        }
        IPage<WareInfoEntity> page = this.page(
                new Query<WareInfoEntity>().getPage(params),
                wrapper
        );

        return new PageUtils(page);
    }

    @Override
    public FareVO getFare(Long addrId) throws ExecutionException, InterruptedException, RRException {
        FareVO fareVO = new FareVO();
        //这里运费的计算考虑对接顺丰开放平台（时效运费查询接口）
        CompletableFuture<CommonSFReq> deliverFuture = CompletableFuture.supplyAsync(() -> {
            CommonSFReq request = new CommonSFReq();
            //1.根据addrId查询收货方地址
            R r1 = memberFeignService.info(addrId);
            if (r1.getCode() == 0) {
                MemberReceiveAddressVO memberReceiveAddress = r1.getData("memberReceiveAddress", new TypeReference<MemberReceiveAddressVO>() {
                });
                fareVO.setReceiveName(memberReceiveAddress.getName());
                fareVO.setPhone(memberReceiveAddress.getPhone());
                request.setReceiverProvince(memberReceiveAddress.getProvince());
                request.setReceiverCity(memberReceiveAddress.getCity());
                request.setReceiverDistrict(memberReceiveAddress.getRegion());
                request.setReceiverAddress(memberReceiveAddress.getDetailAddress());
            }
            return request;
        }, executor);
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<List<CommonSFReq>> taskDeliverFuture = CompletableFuture.supplyAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            //2.查询当前购物车sku对应的仓库地址（发货方地址）。一个sku可能对应多个仓库。目前考虑从有库存的仓库列表中，取第一个仓库作为发货方
            //2.1 查询购物车信息
            R r2 = cartFeignService.getAllSelectedCartItem();
            List<CommonSFReq> requestList = new ArrayList<>();
            if (r2.getCode() == 0) {
                List<CartItemVO> cartItems = r2.getData(new TypeReference<List<CartItemVO>>() {
                });
                requestList = cartItems.stream().map(cartItemVO -> {
                    CommonSFReq request = new CommonSFReq();
                    //2.2 查询当前sku对应第一个库存够的仓库的地址 （sku_id,count）
                    String address = wareSkuService.queryAddress(cartItemVO.getSkuId(), cartItemVO.getCount());
                    if (!StringUtils.isEmpty(address)) {
                        String[] split = address.split("\\|");
                        request.setSenderProvince(split[0]);
                        request.setSenderCity(split[1]);
                        request.setSenderDistrict(split[2]);
                        request.setSenderAddress(split[3]);
                    }
                    //2.3 查询当前购物车项的重量 （单个重量 * 数量）重量在spuInfo里
                    R r = wareSkuFeignService.getWeight(cartItemVO.getSkuId());
                    if (r.getCode() == 0) {
                        BigDecimal weight = r.getData(new TypeReference<BigDecimal>() {
                        });
                        //重量小于1kg按1kg计算，否则顺丰API报错
                        BigDecimal totalWeight = (weight.divide(new BigDecimal(1000))).multiply(new BigDecimal(cartItemVO.getCount()));
                        request.setWeight(totalWeight.compareTo(new BigDecimal(1)) > 1 ? totalWeight : new BigDecimal(1));
                    }
                    return request;
                }).collect(Collectors.toList());
            }
            return requestList;
        }, executor);


        //3.调用时效运费查询接口获取运费返回。多件商品需要查询多次。对所有的运费求和得到最终运费
        CompletableFuture.allOf(deliverFuture, taskDeliverFuture).get();
        CommonSFReq deliver = deliverFuture.get();
        List<CommonSFReq> taskDelivers = taskDeliverFuture.get();
        BigDecimal fare = taskDelivers.stream().map(taskDeliver -> {
            BigDecimal price;
            taskDeliver.setReceiverProvince(deliver.getReceiverProvince());
            taskDeliver.setReceiverCity(deliver.getReceiverCity());
            taskDeliver.setReceiverDistrict(deliver.getReceiverDistrict());
            taskDeliver.setReceiverAddress(deliver.getReceiverAddress());
            taskDeliver.setSuburbFlg(false);
            taskDeliver.setProductCode("S2");
            taskDeliver.setCurrencyType("CN");
            CommonSFResp resp = call(taskDeliver);
            if (resp != null) {
                price = resp.getResultData().getObj().getTotalPrice();
            } else {
                throw new RRException("调用顺丰接口出现异常...");
            }
            return price;
        }).reduce(new BigDecimal(0), (x, y) -> x.add(y));

        fareVO.setAddress(deliver);
        fareVO.setPrice(fare);
        return fareVO;
    }

    public CommonSFResp call(CommonSFReq req) {
        log.info("请求报文：{}", req);
        CommonSFResp resp = new CommonSFResp();
        try {
            CallExpressServiceTools tools = CallExpressServiceTools.getInstance();
            Map<String, String> params = new HashMap<>();
            String timeStamp = String.valueOf(System.currentTimeMillis());
            String msgData = JSON.toJSONString(req);
            params.put("partnerID", sfProperties.getClientNode());  // 顾客编码
            params.put("requestID", UUID.randomUUID().toString().replace("-", ""));
            params.put("serviceCode", sfProperties.getServiceCode());// 接口服务码
            params.put("timestamp", timeStamp);
            params.put("msgData", msgData);
            params.put("msgDigest", tools.getMsgDigest(msgData, timeStamp, sfProperties.getCheckWord()));
            String result = HttpClientUtil.post(sfProperties.getCallUrlBox(), params);
            log.info("===调用地址 ===" + sfProperties.getCallUrlBox());
            log.info("===顾客编码 ===" + sfProperties.getClientNode());
            resp = JSONObject.parseObject(result, CommonSFResp.class);
            String resultData = resp.getApiResultData();
            CommonSFResp.ResultData resp1 = JSONObject.parseObject(resultData, CommonSFResp.ResultData.class);
            resp.setResultData(resp1);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }
        log.info("响应报文：{}", resp);
        return resp;
    }

}